package com.wsl.HealthChallenge.controllers;

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;

import javax.jdo.JDOHelper;
import javax.jdo.PersistenceManager;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;

import com.google.appengine.api.users.User;
import com.google.appengine.api.users.UserService;
import com.google.appengine.api.users.UserServiceFactory;
import com.wsl.HealthChallenge.models.ContestEntry;
import com.wsl.HealthChallenge.models.UserEntry;
import com.wsl.HealthChallenge.utils.DataStorageUtils;
import com.wsl.HealthChallenge.utils.PMF;
import com.wsl.HealthChallenge.utils.Utils;

/**
 * This controller is used to receive the Google Health session auth token and store
 * it in the UserEntry. It expects that the user is already logged into walk2me and that
 * the challenge in the URL exists. It shows a page telling the user to link to Google Health
 * with a link to get the Google Health token. 
 * After receiving the token it stores the authoken in the user entry and redirects
 * to the signup page for the challenge.
 * 
 * @author mark
 */
@Controller
public class LinkToGoogleHealthController {
    @RequestMapping("/{challengeId}/linkToGHealth")
    public ModelAndView handleRequest(@PathVariable String challengeId,
            HttpServletRequest request, HttpServletResponse response) throws Exception {
        // If not logged in, do that first and come back to the same URL.
        if (!Utils.ensureUserLoggedIn(request, response)) {
            return null;
        }

        String googleHealthSessionToken = request.getParameter("gtoken");
        if (googleHealthSessionToken == null) {
            return showLinkToGHealthPage(challengeId, request, response);
        } else {
            storeTokenInUserEntry(challengeId, request, response, googleHealthSessionToken);
            // We added the user now go back to the challenge.
            response.sendRedirect("/" + challengeId + "?signUp=true");
            return null;
        }
    }

    /**
     * Shows a page telling the user to link to his Google Health account.
     * 
     * @param challengeId
     * @param request
     * @param response
     * @return
     * @throws IOException
     */
    private ModelAndView showLinkToGHealthPage(String challengeId,
            HttpServletRequest request, HttpServletResponse response)
            throws IOException {
        ContestEntry challenge = DataStorageUtils.getContest(challengeId);
        if (challenge == null) {
            response.getWriter().print("Error, challenge does not exists: " + challengeId);
            return null;
        }

        ModelMap model = new ModelMap();
        model.addAttribute("challengeName", challenge.getName());
        model.addAttribute("challengeId", challengeId);
        model.addAttribute("userName", request.getUserPrincipal().getName());
        model.addAttribute("signUpUrl", getGhealthLinkUrl(request));

        // TODO(mark): Don't think this is needed, remove this!
        PersistenceManager pm = PMF.get().getPersistenceManager();
        pm.close();

        boolean userClickedSignUp = request.getParameter("signUp") != null;
        if (userClickedSignUp) {
            return new ModelAndView("signup_almost_done_view", model);
        } else {
            return new ModelAndView("signup_with_google_health_view", model);
        }
    }

    /**
     * @param request
     * @return the URL to request the session token from Google Health. 
     * TODO(mark): This currently still uses the redirect to worksmartlabs (which is registered
     * with GH). Change that since wwww.walk2.me is now registered, too. 
     * @throws UnsupportedEncodingException
     */
    private String getGhealthLinkUrl(HttpServletRequest request)
            throws UnsupportedEncodingException {
        // TODO(mark): Get rid of redirecting to worksmartlabs here to receive the session token.
        String thisUrl = request.getRequestURL().toString();
        String next =
            "http://www.worksmartlabs.com:8080/GHealthToken/exchangeTokenProd?w2mnext=" + 
            URLEncoder.encode(thisUrl, "UTF-8");
        String url = 
            "https://www.google.com/health/authsub?next=" +
            URLEncoder.encode(next, "UTF-8") +
            "&scope=https%3A%2F%2Fwww.google.com%2Fhealth%2Ffeeds%2F&secure=1&session=1&permission=1";
        return url;
    }

    /**
     * Stores the the Google Health auth token with the user entry in the data store.
     * If needed inserts a new user entry.
     * @param challengeId
     * @param request
     * @param response
     * @param googleHealthSessionToken
     * @throws IOException
     */
    private void storeTokenInUserEntry(String challengeId,
            HttpServletRequest request, HttpServletResponse response,
            String googleHealthSessionToken) throws IOException {
        UserService userService = UserServiceFactory.getUserService();
        User user = userService.getCurrentUser();

        // TODO(mark): Share this code with the challenge creation controller.
        UserEntry userEntry = DataStorageUtils.getUserEntry(user.getUserId());
        if (userEntry == null) {
            userEntry = new UserEntry(user.getUserId(), 
                    request.getUserPrincipal().getName(),
                    user.getEmail(), googleHealthSessionToken);
        } else {
            userEntry.setGoogleHealthSessionToken(googleHealthSessionToken);
            JDOHelper.makeDirty(userEntry, "googleHealthSessionToken"); 
        }
        DataStorageUtils.insertOrUpdateUser(userEntry);
    }
}